LCS Algorithm

#Algorithm #Algorithm_LCS

마이구미의 HelloWorld, 마이구미 님의 블로그를 참고하여 정리했습니다.

1. (Longest Common) Substring과 Subsequence의 차이

두 문자열 'ABCDHEFQZEX'와 'UBCDEFLQZEXKK'를 가지고 LCSubstring과 LCSubsequence를 구해보자. 우선 각 문자열의 공통 문자열을 체크하면 다음과 같다.

lcs_example_string.png|400

이렇게 되었을 때, LCSubstring은 'QZEX' (문자열 길이가 4로 제일 김), LCSubsequence는 'BCDEFQZEX'가 된다.
lcs_example_explain.png|500


2. 수식

두 LCS는 수식으로 볼 때 이해가 가장 빠른 것 같다. 최장 공통 부분 문자열을 찾아내기 위한 알고리즘의 수식은 다음과 같다. 2차원 배열에 문자열의 문자가 하나씩 나열되어 있고, 그 안의 값은 최대 문자열의 문자수 혹은 수열의 문자 개수라고 생각하자 (0은 문자가 없는 것을 의미하며 인덱스0 행과 0열은 모두 0으로 채워진다.)
lcs_array.png|400

2-1. LCS - Longest Common Substring (최장 공통 부분 문자열)

문자열 S와 문자열 T를 가지고 할 때,

LCSubstring(Sp,Tq)={LCSubstring(Sp1,Tq1)+1ifS[p]=T[q]0otherwise

[p]행의 문자와 [q]열의 문자가

2-2. LCS - Longest Common Subsequence (최장 공통 부분 수열)

LCSubsequence(Sp,Tq)={0ifp=0orq=0LCSubsequence(Sp1,Tq1)+1ifS[p]=T[q]longest(LCSubsequence(Sp1,Tq),LCSubsequence(Sp,Tq1))ifS[p]T[q]

[p]행의 문자와 [q]열의 문자가


3. 구현

3-1. 알고리즘

public class LCS {

    static int findLCSubstring(String s, String t) {
        int[][] LCS = new int[s.length() + 1][t.length() + 1];
        int maxLength = 0;

        for (int i = 1; i <= s.length(); i++) {
            for (int j = 1; j <= t.length(); j++) {
                if (s.charAt(i - 1) == t.charAt(j - 1)) {
                    LCS[i][j] = LCS[i - 1][j - 1] + 1;

                    if (maxLength < LCS[i][j]) {
                        maxLength = LCS[i][j];
                    }
                }
            }
        }

        return maxLength;
    }

    static int findLCSubsequence(String s, String t) {
        int[][] LCS = new int[s.length() + 1][t.length() + 1];

        for (int i = 1; i <= s.length(); i++) {
            for (int j = 1; j <= t.length(); j++) {
                if (s.charAt(i - 1) == t.charAt(j - 1)) {
                    LCS[i][j] = LCS[i - 1][j - 1] + 1;
                } else {
                    LCS[i][j] = Math.max(LCS[i - 1][j], LCS[i][j-1]);
                }
            }
        }

        return LCS[s.length()][t.length()];
    }
}

3-2. 테스트

public class LCSTest {
    public static void main(String[] args) {
        LCS lcs = new LCS();

        String s = "ABCDHEFQZEX";
        String t = "UBCDEFLQZEXKK";

        int lcsSubstring = lcs.findLCSubstring(s, t);
        int lcsSubsequence = lcs.findLCSubsequence(s, t);

        System.out.println("lcsSubstring=" + lcsSubstring + ", lcsSubsequence=" + lcsSubsequence); // lcsSubstring=4, lcsSubsequence=9

    }
}

4. 관련 문제

4-1. LCSubstring

4-2. LCSubsequence

1143. Longest Common Subsequence